
local meta = FindMetaTable( "Player" )
if (!meta) then return end 

function meta:PickTeam()
	if team.NumPlayers(1) == team.NumPlayers(2) then
		self:SetTeam(math.random(1,2))
		self:ChatPrint("You have been randomly placed on a team.")
	elseif team.NumPlayers(1) > team.NumPlayers(2) then
		self:SetTeam(2)
		self:ChatPrint("You are on the Blue team now.")
	else
		self:SetTeam(1)
		self:ChatPrint("You are on the Red team now.")
	end
end

function meta:ChooseTeam()
	local vteam = self:Team()
	local vteam2
	if vteam == 1 then
		vteam2 = 2
	else
		vteam2 = 1 
	end
	if team.NumPlayers(vteam) == team.NumPlayers(vteam2) then
		self:ChatPrint("The teams are even, moron.")
	elseif team.NumPlayers(vteam) > team.NumPlayers(vteam2) then
		self:SetTeam(vteam2)
		self:Spawn()
		self:CleanupVehicle(true)
		self:ChatPrint("You have swapped teams.")
	else
		self:ChatPrint("The teams are uneven, unable to change teams.")
	end
end

function meta:CleanupVehicle(fx)
	if self.CurVehicle then
		if fx then
			local num = math.Round(self.CurVehicle:MaxVehicleHealth() / 35)
			if num < 4 then num = 6 end
			for i=0,num do
				local effectdata = EffectData()
				effectdata:SetOrigin(self.CurVehicle:GetPos())
				effectdata:SetAngle(self.CurVehicle:GetAngles())
				util.Effect("prop_directional_gib", effectdata)
			end
			num = math.Clamp(num/2,1,10)
			for i=1,num do
				local effectdata = EffectData()
				effectdata:SetOrigin(self.CurVehicle:GetPos())
				util.Effect("prop_gib", effectdata)
			end
			local effectdata = EffectData()
			effectdata:SetOrigin(self.CurVehicle:GetPos())
			effectdata:SetScale(self.CurVehicle:MaxVehicleHealth())
			util.Effect("vehicle_explosion", effectdata)
			self.CurVehicle:EmitSound(Sound(ChooseRandom(GameSounds.VehicleExplosion)),100,math.random(95,105))
			self.CurVehicle:EmitSound(Sound(ChooseRandom(GameSounds.ExplosionDebris)),100,math.random(80,100))
		end
		self.CurVehicle:Destroy() //SENT function.
		self.IsInVehicle = false
		self.CurVehicle = nil
		self:SetNetworkedEntity("CurVehicle",nil)
	end
end

function meta:DestroyVehicle(attacker)
	if self.CurVehicle and self.IsInVehicle then
		self:Spawn()
		self:SetPos(self.CurVehicle:GetPos()+Vector(0,0,10))
		self.DeathType = "explosion"
		if attacker and attacker:IsValid() and attacker:IsPlayer() then
			self:TakeDamage(9999,attacker)
			for i=1,math.random(2,3) do
				local effectdata = EffectData()
				effectdata:SetOrigin(self.CurVehicle:GetPos())
				util.Effect("corpse_gib", effectdata)
			end
		else
			self:Kill()
		end
		umsg.Start("IsInVehicle",self)
		umsg.Short(6)
		umsg.End()
	end
	self:CleanupVehicle(true)
end

function meta:ExitVehicle()
	if self.CurVehicle and self.IsInVehicle then
	
		self:SetMoveType(MOVETYPE_WALK)
		self.CurVehicle:EndSoundLoop()
		self.CurVehicle:GetWeapon():SetUser(nil)
		self.CurVehicle:SetDriver(nil)
		self:Spawn()
		
		self:EmitSound(Sound("vehicles/atv_ammo_close.wav"),100,math.random(90,110))
		
		self:SetPos(self.CurVehicle:GetPos()+Vector(0,0,10))
		self:SetVelocity(self.CurVehicle:GetVelocity())
		self.IsInVehicle = false
		
		umsg.Start("IsInVehicle",self)
		umsg.Short(6)
		umsg.End()
		umsg.Start("IsMayday", self)
		umsg.Short(6)
		umsg.End()
		
		local start = self:GetPos()
		local finish = self:GetPos() + Vector(0,0,-500)
		local tracedata = {}
        tracedata.start = start
        tracedata.endpos = finish
		tracedata.filter = self
        local tr = util.TraceLine(tracedata) 
		if self.Class == "Pilot" and not tr.Hit then
			self:EmitSound(Sound(ChooseRandom(GameSounds.WindGusts)),100,math.random(100,110))
		end
	end
end

function meta:EnterVehicle(vehicle)
	if vehicle:GetOwner() == self then
		self:DoExtinguish()
		self:SetMoveType(MOVETYPE_NOCLIP)
		self:SetColor(Color(0,0,0,0))
		vehicle:SetDriver(self)
		self:StripWeapons()
		
		local vclass = self.CurVehicle:GetWeapon():GetClass()
		self:Give(vclass.."_weapon")
		self.CurHealth = self:Health()
		self.IsInVehicle = true
		
		self:EmitSound(Sound("vehicles/atv_ammo_open.wav"),100,math.random(90,110))
		
		umsg.Start("IsInVehicle",self)
		umsg.Short(5)
		umsg.End()
		
		self:SetEyeAngles(vehicle:GetTrueAngles())
	end
end

function meta:LookupTable(tbl,name)
	for k,v in pairs(tbl) do
		if v.Name == name then
			return tbl[k]
		end
	end
end

function meta:BuildVehicle()

	if self.CurVehicle then self:ChatPrint("You already have a vehicle!") return end

	if (self.Class == "Soldier") then return end
	if (self.Class == "Rocketeer") then return end
	local bpos
	for k,v in pairs(ents.FindByClass("sent_vehiclepad")) do
		if v:GetTeam() == self:Team() then
			bpos = v
		end
	end
	local pos = bpos:GetPos() + Vector(0,0,50)
	local etbl = ents.FindInSphere(pos,400)
	for k,v in pairs(etbl) do
		if string.find(v:GetClass(),"vehicle_") then
			self:ChatPrint("There is something blocking your vehicle spawn pad!") 
			return
		end
	end
	
	if self:GetModel() == "models/player/barney.mdl" then
		local tbl = self:LookupTable(Vehicles.Aircrafts.Torsos,self.Vehicle.Air.Torso)
		local tbl2 = self:LookupTable(Vehicles.Aircrafts.Wings,self.Vehicle.Air.Wings)
		local tbl3 = self:LookupTable(Vehicles.Aircrafts.Weapons,self.Vehicle.Air.Weapon)
		
		//permanent angle offset MAY need to be applied.
		
		local ent2 = ents.Create( "vehicle_part" )
		ent2:SetPos( pos + Vector(0,0,40) )
		ent2:SetAngles(tbl2.Offset)
		ent2:SetPlayer(self)
		ent2:Setup(tbl2.Model,team.GetColor(self:Team()))
		ent2:Spawn()
		ent2:Activate()
		ent2:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
		
		local ent = ents.Create( "vehicle_air"..tbl.NameExt )
		ent:SetPos( pos )
		ent:SetAngles(tbl.Offset)
		ent:SetPlayer(self)
		ent:Setup(tbl.Model,(tbl.Drag+tbl2.Drag),(tbl.Health+tbl2.Health),team.GetColor(self:Team()),tbl.Offset, {ent2})
		ent:Spawn()
		ent:Activate()
		
		local ent3 = ents.Create(tbl3.SentName)
		if tbl3.Mount == "frontal" then
			ent3:SetPos(ent:GetPos() + ent:GetTrueForward()*50)
		else
			ent3:SetPos(ent:GetPos())
		end
		ent3:Setup(tbl3.Offset)
		ent3:SetPlayer(ent:GetOwner())
		ent3:SetAngles(tbl3.Offset)
		ent3:Activate()
		ent3:Spawn()
		ent:UpdateParts({ent2,ent3})
		
		local start = ent3:GetPos() + Vector(0,0,-2)
		local finish = ent:GetPos()
		local tracedata = {}
        tracedata.start = start
        tracedata.endpos = finish
		tracedata.filter = ent3
        local tr = util.TraceLine(tracedata) 
		
		ent3:SetPos(tr.HitPos)
		ent3:SetParent(ent)
		
		local start = pos + Vector(0,0,50)
		local finish = pos - Vector(0,0,900)
		local tracedata = {}
        tracedata.start = start
        tracedata.endpos = finish
		tracedata.filter = ent2
        local tr = util.TraceLine(tracedata) 
		
		ent2:SetPos(tr.HitPos + tbl2.Add)
		
		ent2:SetParent(ent)
		//constraint.Weld( ent, ent2, tr.PhysicsBone, tr.PhysicsBone, 0, false ) 
		
		local phys = ent2:GetPhysicsObject()
		if phys and phys:IsValid() then
			phys:SetMass(1)
			phys:EnableMotion(true)
			phys:ApplyForceCenter(Vector(0,0,1))
		end
		phys = ent:GetPhysicsObject()
		if phys and phys:IsValid() then
			phys:SetMass(100)
			phys:EnableMotion(true)
			phys:ApplyForceCenter(Vector(0,0,1))
		end
		
		self.CurVehicle = ent
		
	elseif self:GetModel() == "models/player/combine_soldier.mdl" then
		local tbl = self:LookupTable(Vehicles.Land.Torsos,self.Vehicle.Land.Torso)
		local tbl2 = self:LookupTable(Vehicles.Land.Wheels,self.Vehicle.Land.Wheels)
		local tbl3 = self:LookupTable(Vehicles.Land.Weapons,self.Vehicle.Land.Weapon)
		
		local ent = ents.Create( "vehicle_land"..tbl.NameExt )
		ent:SetPos( pos )
		ent:SetAngles(tbl.Offset)
		ent:SetPlayer(self)
		ent:Setup(tbl.Model,(tbl.Drag+tbl2.Drag),(tbl.Health+tbl2.Health),team.GetColor(self:Team()),tbl.Offset,{})
		ent:Spawn()
		ent:Activate()
		
		umsg.Start("CurVehicleOffset",self)
		umsg.Angle(tbl.Offset)
		umsg.End()
		
		local ent2 = ents.Create( "vehicle_part" )
		ent2:SetPos( ent:GetPos() + Vector(0,50,0) )
		ent2:SetAngles(tbl2.Offset)
		ent2:SetPlayer(self)
		ent2:Setup(tbl2.Model,team.GetColor(self:Team()))
		ent2:Spawn()
		ent2:Activate()
		ent2:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
		
		local ent3 = ents.Create( "vehicle_part" )
		ent3:SetPos( ent:GetPos() + Vector(0,-50,0) )
		ent3:SetAngles(tbl2.Offset)
		ent3:SetPlayer(self)
		ent3:Setup(tbl2.Model,team.GetColor(self:Team()))
		ent3:Spawn()
		ent3:Activate()
		ent3:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
		
		local ent4 = ents.Create(tbl3.SentName)
		if tbl3.Mount == "frontal" then
			ent4:SetPos(ent:GetPos() + ent:GetTrueForward()*50)
		else
			ent4:SetPos(ent:GetPos()+ ent:GetTrueUp()*60)
		end
		ent4:Setup(tbl3.Offset)
		ent4:SetPlayer(ent:GetOwner())
		ent4:SetAngles(tbl3.Offset)
		ent4:Activate()
		ent4:Spawn()
		
		local start = ent4:GetPos()
		local finish = ent:GetPos()
		local tracedata = {}
        tracedata.start = start
        tracedata.endpos = finish
		tracedata.filter = ent4
        local tr = util.TraceLine(tracedata) 
		
		ent4:SetPos(tr.HitPos)
		ent4:SetParent(ent)
		
		ent:UpdateParts({ent2,ent3,ent4})
		
		local start = ent:GetPos() + (ent:GetRight() * 50) //positive or neg?
		local finish = ent:GetPos() + (ent:GetRight() * -900)
		local tracedata = {}
        tracedata.start = start
        tracedata.endpos = finish
		tracedata.filter = ent2
        local tr = util.TraceLine(tracedata) 
		
		ent2:SetPos(tr.HitPos)
		 
		ent2:SetParent(ent)
		//constraint.Weld( ent, ent2, tr.PhysicsBone, tr.PhysicsBone, 0, false ) 
		//constraint.Axis( ent, ent2, tr.PhysicsBone, tr.PhysicsBone, ent:GetPos(), ent2:GetPos(), 0, 0, 0, 0 )
		
		local start = ent:GetPos() + (ent:GetRight() * -50)
		local finish = ent:GetPos() + (ent:GetRight() * 900)
		local tracedata = {}
        tracedata.start = start
        tracedata.endpos = finish
		tracedata.filter = ent3
        local tr = util.TraceLine(tracedata) 
		
		ent3:SetPos(tr.HitPos)
		 
		ent3:SetParent(ent)
		//constraint.Weld( ent, ent3, tr.PhysicsBone, tr.PhysicsBone, 0, false ) 
		//constraint.Axis( ent, ent3, tr.PhysicsBone, tr.PhysicsBone, ent:GetPos(), ent3:GetPos(), 0, 0, 0, 0 )
		
		local phys = ent2:GetPhysicsObject()
		if phys and phys:IsValid() then
			phys:SetMass(1)
			phys:EnableMotion(true)
			phys:ApplyForceCenter(Vector(0,0,1))
		end
		phys = ent3:GetPhysicsObject()
		if phys and phys:IsValid() then
			phys:SetMass(1)
			phys:EnableMotion(true)
			phys:ApplyForceCenter(Vector(0,0,1))
		end
		phys = ent:GetPhysicsObject()
		if phys and phys:IsValid() then
			phys:SetMass(100)
			phys:EnableMotion(true)
			phys:ApplyForceCenter(Vector(0,0,1))
		end
		
		self.CurVehicle = ent
		
	end
	self:SetNetworkedEntity("CurVehicle",self.CurVehicle)
end

function meta:GetVehicle()
return self.CurVehicle end

function meta:SetVehicle(v)
	self.CurVehicle = v 
end

// Player should be on fire for the next x seconds
function meta:SetFireTime( add )
	self.FireTimer = CurTime() + add 
end

// Returns the amount of seconds left being on fire
function meta:GetFireTime( add )
	return (self.FireTimer or 0) - CurTime()
end

function meta:DoExtinguish()
	self:SetFireTime( -1 )
	self.FireAttacker = nil
	self:SetNetworkedBool("onfire",false)
end

function meta:DoIgnite( attacker )
	self:EmitSound(Sound("ambient/fire/mtov_flame2.wav"),100,math.random(90,110))
	//self:EmitSound(Sound("ambient/fire/fire_small1.wav"),100,100)
	//local burn = Sound("NPC_HeadCrab.Burning")
	//self.FireSound = CreateSound(self,FleshBurn)
	//self.FireSound:Play()
	self:SetFireTime( math.random(5,9) )
	if attacker == self then
		self.FireAttacker = nil
		return
	end
	self.FireAttacker = attacker
end

function meta:DoNapalmIgnite( attacker )
	self:EmitSound(Sound("ambient/fire/mtov_flame2.wav"),120,math.random(90,110))
	self:SetFireTime( math.random(12,17) )
	if attacker == self then
		self.FireAttacker = nil
		return
	end
	self.FireAttacker = attacker
end

function meta:Think( )
	//self:AddRecoil()
	//self:DoOnFire()
end

function meta:DoOnFire()
	local OnFire = self.OnFire

	if self:GetFireTime() <= 0 then
		if (OnFire) then
			self.OnFire = false
			self:SetNetworkedBool("onfire",false)
		end
	return end
	
	if not OnFire then
		self.OnFire = true
		self:SetNetworkedBool("onfire",true)
	end
	
	// Do server effects (take damage)
	if SERVER and (self.LastFire or 0) < CurTime() and self.OnFire then
	
		self.LastFire = CurTime() + 0.1 
		self.DeathType = "burn"
		self.Interval = self.Interval or 1
		local rand = math.random(1,10)
		if rand < 4 then
			self.Interval = self.Interval + 1
			if self.Interval > 5 then
				if rand == 1 then
					self:EmitSound(Sound(ChooseRandom(self.Pain)),100,100)
				else
					self:EmitSound(ChooseRandom(GameSounds.Burn),100,math.random(95,105))
				end
				self.Interval = 1
			end
		end
		if self.FireAttacker and self.FireAttacker != self then
			self:TakeDamage( 1, self.FireAttacker, self.FireAttacker )
		else
			self:SetHealth(self:Health() - 1)
			if self:Health() <= 0 then
				self.Death = GameSounds.Burn
				self:DoExtinguish()
				self:Kill()
			end
		end
	end
	
	// Do clientside effects (move the view)
	if CLIENT and (self.LastFire or 0) < CurTime() then
		if (self == LocalPlayer()) then
			//self:Recoil( math.Rand( -3, 3 ), math.Rand( -15, 15 ) )
		end
	end
end

function meta:BecomeStealth()

	local prop = self:GetProp()
	if (prop == nil) or !prop:IsValid() then self:PropCleanup() return end
	local phys = prop:GetPhysicsObject()
	if (phys == nil) or !phys:IsValid() then self:PropCleanup() return end
	
	local effectdata = EffectData()
	effectdata:SetEntity(prop)
	util.Effect("prop_stealth", effectdata)
	
	//local refract = Material( "models/spawn_effect" )
	prop.OriginalMaterial = prop:GetMaterial()
	prop:SetMaterial("sprites/heatwave")

	timer.Simple(7,GAMEMODE.ResetMaterial, GAMEMODE, prop)

end

function meta:GetVar( name, default )

	local Val = self:GetTable()[ name ]
	if ( Val == nil ) then return default end
	
	return Val
	
end

function meta:SetVar( name, value )
	self:GetTable()[ name ] = value
end

function meta:SetScore(value)
	self:SetNetworkedFloat("score",value)
end

function meta:GetScore()
	return self:GetNetworkedFloat("score") or 0
end

function meta:AddScore(value)
	self:SetNetworkedFloat("score",(self:GetNetworkedFloat("score") or 0) + value)
end

function meta:SetKills(value)
	self:SetNetworkedFloat("frags",value)
end

function meta:GetKills()
	return self:GetNetworkedFloat("frags") or 0
end

function meta:AddKills(value)
	self:SetNetworkedFloat("frags",(self:GetNetworkedFloat("frags") or 0) + value)
end

function meta:Recoil( pitch, yaw )

	// People shouldn't really be playing in SP
	// But when they are they won't get recoil because the weapons aren't predicted
	// So the clientside stuff never fires the recoil
	if ( SERVER && SinglePlayer() ) then 
	
		// Please don't call SendLua in multiplayer games. This uses a lot of bandwidth
		self:SendLua( "LocalPlayer():Recoil("..pitch..","..yaw..")" )
		return 
		
	end
	
	self:GetTable().RecoilYaw = self:GetTable().RecoilYaw or 0
	self:GetTable().RecoilPitch = self:GetTable().RecoilPitch or 0
	
	self:GetTable().RecoilYaw = self:GetTable().RecoilYaw 		+ yaw
	self:GetTable().RecoilPitch = self:GetTable().RecoilPitch 	+ pitch

end


function meta:HeadShot()

	self:GetTable().HeadShotRoll = 25
	self:GetTable().HeadShotStart = CurTime()
	
	MotionBlur = 0.85
	ColorModify[ "$pp_colour_colour" ] = 0
	ColorModify[ "$pp_colour_addr" ] = 1
//	ColorModify[ "$pp_colour_mulr" ] = 2
	Sharpen = 2

end

function meta:BodyShot()

	//self:GetTable().HeadShotRoll = math.Clamp( self:GetTable().HeadShotRoll + 10, 0, 45 )
	//self:GetTable().HeadShotStart = CurTime()
	
	//ColorModify[ "$pp_colour_addr" ] = 1
	//ColorModify[ "$pp_colour_mulr" ] = 2

end

function meta:AddRecoil( pitch, yaw )

	if ( SERVER ) then return end
	if ( self != LocalPlayer() ) then return end
	
	local pitch 	= self:GetTable().RecoilPitch	or 0
	local yaw 		= self:GetTable().RecoilYaw  	or 0
	
	local pitch_d	= math.Approach( pitch, 0.0, 20.0 * FrameTime() * math.abs(pitch) )
	local yaw_d		= math.Approach( yaw, 0.0, 20.0 * FrameTime() * math.abs(yaw) )
	
	self:GetTable().RecoilPitch 	= pitch_d
	self:GetTable().RecoilYaw 		= yaw_d
		
	// Update eye angles
	local eyes = self:EyeAngles()
		eyes.pitch = eyes.pitch + ( pitch - pitch_d )
		eyes.yaw = eyes.yaw + ( yaw - yaw_d )
		eyes.roll = 0
	self:SetEyeAngles( eyes )

end

function meta:TraceAttack( dmginfo, dir, trace )

	if ( trace.HitGroup == HITGROUP_HEAD ) then
	
		local effectdata = EffectData()
			effectdata:SetEntity( self )
			effectdata:SetOrigin( trace.HitPos )
			effectdata:SetNormal( dir )
		util.Effect( "headshot", effectdata )
		return
		
	end
	
	local effectdata = EffectData()
		effectdata:SetEntity( self )
		effectdata:SetOrigin( trace.HitPos )
		effectdata:SetNormal( trace.HitNormal )
	util.Effect( "bodyshot", effectdata )

end



function meta:TraceLine( distance )

	local vStart = self:GetShootPos()
	local vForward = self:GetAimVector()

	local trace = {}
	trace.start = vStart
	trace.endpos = vStart + (vForward * distance)
	trace.filter = self
		
	return util.TraceLine( trace )

end

function meta:GetCustomAmmo( name )
	return self:GetNWInt( "ammo_" .. name )
end

function meta:SetCustomAmmo( name, num )
	return self:SetNWInt( "ammo_" .. name, num )
end

function meta:AddCustomAmmo( name, num )
	return self:SetCustomAmmo( name, self:GetCustomAmmo( name ) + num )
end

